dbpath = "domain"
"""Table of domain info indexed by domain id."""
- domain = {}
+ domain_by_id = {}
+ domain_by_name = {}
"""Table of domains to restart, indexed by domain id."""
- restarts = {}
+ restarts_by_id = {}
+ restarts_by_name = {}
"""Table of delayed calls."""
schedule = {}
def __init__(self):
+ # Hack alert. Python does not support mutual imports, but XendDomainInfo
+ # needs access to the XendDomain instance to look up domains. Attempting
+ # to import XendDomain from XendDomainInfo causes unbounded recursion.
+ # So we stuff the XendDomain instance (self) into XendDomainInfo's
+ # namespace as 'xd'.
+ XendDomainInfo.xd = self
# Table of domain info indexed by domain id.
self.db = XendDB.XendDB(self.dbpath)
self.domain_db = self.db.fetchall("")
@return: deferred
"""
def cbok(dominfo):
- self.domain[dominfo.id] = dominfo
+ self.domain_by_id[dominfo.id] = dominfo
+ self.domain_by_name[dominfo.name] = dominfo
if dominfo.restart_pending():
self.domain_restart_add(dominfo)
deferred.addCallback(cbok)
return deferred
- def _add_domain(self, id, info, notify=1):
+ def _add_domain(self, info, notify=1):
"""Add a domain entry to the tables.
- @param id: domain id
@param info: domain info object
@param notify: send a domain created event if true
"""
- self.domain[id] = info
- self.domain_db[id] = info.sxpr()
- self.sync_domain(id)
- if notify: eserver.inject('xend.domain.created', id)
+ self.domain_by_id[info.id] = info
+ self.domain_db[info.id] = info.sxpr()
+ self.domain_by_name[info.name] = info
+ self.sync_domain(info.id)
+ if notify: eserver.inject('xend.domain.created', info.name)
def _delete_domain(self, id, notify=1):
"""Remove a domain from the tables.
@param id: domain id
@param notify: send a domain died event if true
"""
- if id in self.domain:
- if notify: eserver.inject('xend.domain.died', id)
- del self.domain[id]
+ if id in self.domain_by_id:
+ info = self.domain_by_id[id]
+ if notify: eserver.inject('xend.domain.died', info.name)
+ if info.name in self.domain_by_name:
+ del self.domain_by_name[info.name]
+ del self.domain_by_id[id]
if id in self.domain_db:
del self.domain_db[id]
self.db.delete(id)
if reason in ['poweroff', 'reboot']:
self.domain_restart_schedule(id, reason)
self.final_domain_destroy(id)
- if len(self.restarts):
+ if self.domain_restarts_exist():
self.domain_restarts_schedule()
def refresh(self):
for d in domlist:
id = str(d['dom'])
doms[id] = d
- if id not in self.domain:
+ if id not in self.domain_by_id:
savedinfo = None
deferred = XendDomainInfo.vm_recreate(savedinfo, d)
def cbok(dominfo):
- self._add_domain(dominfo.id, dominfo)
+ self._add_domain(dominfo)
deferred.addCallback(cbok)
# Remove entries for domains that no longer exist.
- for d in self.domain.values():
+ for d in self.domain_by_id.values():
info = doms.get(d.id)
if info:
d.update(info)
@param id: domain id
"""
- dominfo = self.domain.get(id)
+ dominfo = self.domain_by_id.get(id)
if dominfo:
self.domain_db[id] = dominfo.sxpr()
self.sync_domain(id)
raise
pass
else:
- d = self.domain.get(id)
+ d = self.domain_by_id.get(id)
if d:
d.update(dominfo[0])
def domain_ls(self):
+ """Get list of domain names.
+
+ @return: domain names
+ """
+ self.refresh()
+ return self.domain_by_name.keys()
+
+ def domain_ls_ids(self):
"""Get list of domain ids.
- @return: domain ids
+ @return: domain names
"""
self.refresh()
- return self.domain.keys()
+ return self.domain_by_id.keys()
def domains(self):
"""Get list of domain objects.
@return: domain objects
"""
self.refresh()
- return self.domain.values()
+ return self.domain_by_id.values()
def domain_create(self, config):
"""Create a domain from a configuration.
@return: deferred
"""
def cbok(dominfo):
- self._add_domain(dominfo.id, dominfo)
+ self._add_domain(dominfo)
return dominfo
deferred = XendDomainInfo.vm_create(config)
deferred.addCallback(cbok)
@return: deferred
"""
def cbok(dominfo):
- self._add_domain(dominfo.id, dominfo)
+ self._add_domain(dominfo)
return dominfo
log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
deferred = dominfo.restart()
@param config: configuration
@return: deferred
"""
- log.debug('domain_configure> id=%s config=%s', id, str(config))
- dom = int(id)
- dominfo = self.domain_get(dom)
+ dominfo = self.domain_get(id)
if not dominfo:
raise XendError("Invalid domain: " + str(id))
+ log.debug('domain_configure> id=%s config=%s', id, str(config))
if dominfo.config:
- raise XendError("Domain already configured: " + str(id))
+ raise XendError("Domain already configured: " + dominfo.name)
def cbok(dominfo):
- self._add_domain(dominfo.id, dominfo)
+ self._add_domain(dominfo)
return dominfo
deferred = dominfo.construct(config)
deferred.addCallback(cbok)
"""
def cbok(dominfo):
- self._add_domain(dominfo.id, dominfo)
+ self._add_domain(dominfo)
return dominfo
deferred = XendDomainInfo.vm_restore(src, progress=progress)
deferred.addCallback(cbok)
"""
id = str(id)
self.refresh_domain(id)
- return self.domain.get(id)
-
+ return self.domain_by_id.get(id)
+
+ def domain_lookup(self, name):
+ name = str(name)
+ dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
+ if dominfo:
+ return dominfo
+ raise XendError('invalid domain:' + name)
+
+ def domain_exists(self, name):
+ name = str(name)
+ if self.domain_by_name.get(name) or self.domain_by_id.get(name):
+ return 1
+ else:
+ return 0
+
def domain_unpause(self, id):
"""Unpause domain execution.
@param id: domain id
"""
- dom = int(id)
- eserver.inject('xend.domain.unpause', id)
- return xc.domain_unpause(dom=dom)
+ dominfo = self.domain_lookup(id)
+ eserver.inject('xend.domain.unpause', dominfo.name)
+ return xc.domain_unpause(dom=dominfo.dom)
def domain_pause(self, id):
"""Pause domain execution.
@param id: domain id
"""
- dom = int(id)
- eserver.inject('xend.domain.pause', id)
- return xc.domain_pause(dom=dom)
+ dominfo = self.domain_lookup(id)
+ eserver.inject('xend.domain.pause', dominfo.name)
+ return xc.domain_pause(dom=dominfo.dom)
def domain_shutdown(self, id, reason='poweroff'):
"""Shutdown domain (nicely).
@param id: domain id
@param reason: shutdown type: poweroff, reboot, suspend, halt
"""
- dom = int(id)
- id = str(id)
- if dom <= 0:
- return 0
+ dominfo = self.domain_lookup(id)
if reason == 'halt':
- self.domain_restart_cancel(id)
+ self.domain_restart_cancel(dominfo.id)
else:
- self.domain_restart_schedule(id, reason, force=1)
- eserver.inject('xend.domain.shutdown', [id, reason])
+ self.domain_restart_schedule(dominfo.id, reason, force=1)
+ eserver.inject('xend.domain.shutdown', [dominfo.name, reason])
if reason == 'halt':
reason = 'poweroff'
- val = xend.domain_shutdown(dom, reason)
+ val = xend.domain_shutdown(dominfo.id, reason)
self.refresh_schedule()
return val
@param reason: shutdown reason
"""
log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
- dominfo = self.domain.get(id)
+ dominfo = self.domain_lookup(id)
if not dominfo:
return
- if id in self.restarts:
+ if dominfo.id in self.restarts_by_id:
return
restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
if restart:
self.domain_restart_add(dominfo)
def domain_restart_add(self, dominfo):
- self.restarts[dominfo.id] = dominfo
- log.info('Scheduling restart for domain: id=%s name=%s', dominfo.id, dominfo.name)
+ self.restarts_by_name[dominfo.name] = dominfo
+ self.restarts_by_id[dominfo.id] = dominfo
+ log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
self.domain_restarts_schedule()
def domain_restart_cancel(self, id):
@param id: domain id
"""
- dominfo = self.restarts.get(id)
+ dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
if dominfo:
- log.info('Cancelling restart for domain: id=%s name=%s', dominfo.id, dominfo.name)
+ log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
dominfo.restart_cancel()
- del self.restarts[id]
+ del self.restarts_by_id[dominfo.id]
+ del self.restarts_by_name[dominfo.name]
def domain_restarts(self):
"""Execute any scheduled domain restarts for domains that have gone.
"""
self.domain_restarts_cancel()
- for id in self.restarts.keys():
- if id in self.domain:
+ for dominfo in self.restarts_by_id.values():
+ if dominfo.id in self.domain_by_id:
# Don't execute restart for domains still running.
continue
- dominfo = self.restarts[id]
# Remove it from the restarts.
- del self.restarts[id]
+ del self.restarts_by_id[dominfo.id]
+ del self.restarts_by_name[dominfo.name]
try:
def cbok(dominfo):
- log.info('Restarted domain id=%s as %s', id, dominfo.id)
+ log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
self.domain_unpause(dominfo.id)
def cberr(err):
- log.exception("Delayed exception restarting domain: id=%s", id)
+ log.exception("Delayed exception restarting domain: name=%s id=%s",
+ dominfo.name, dominfo.id)
deferred = self.domain_restart(dominfo)
deferred.addCallback(cbok)
deferred.addErrback(cberr)
except:
- log.exception("Exception restarting domain: id=%s", id)
- if len(self.restarts):
+ log.exception("Exception restarting domain: name=%s id=%s",
+ dominfo.name, dominfo.id)
+ if self.domain_restarts_exist():
# Run again later if any restarts remain.
self.refresh_schedule(delay=5)
+
+ def domain_restarts_exist(self):
+ return len(self.restarts_by_id)
def final_domain_destroy(self, id):
"""Final destruction of a domain..
@param id: domain id
"""
- dom = int(id)
- if dom <= 0:
- return 0
- log.info('Destroying domain: id=%s', str(id))
- eserver.inject('xend.domain.destroy', id)
- dominfo = self.domain.get(id)
+ dominfo = self.domain_lookup(id)
+ log.info('Destroying domain: name=%s', dominfo.name)
+ eserver.inject('xend.domain.destroy', dominfo.name)
if dominfo:
val = dominfo.destroy()
else:
- val = xc.domain_destroy(dom=dom)
+ #todo
+ val = xc.domain_destroy(dom=dominfo.dom)
return val
def domain_destroy(self, id, reason='halt'):
@param id: domain id
"""
- id = str(id)
if reason == 'halt':
self.domain_restart_cancel(id)
elif reason == 'reboot':
# Need a cancel too?
# Don't forget to cancel restart for it.
print 'domain_migrate>', id, dst
- dom = int(id)
+ dominfo = self.domain_lookup(id)
xmigrate = XendMigrate.instance()
- val = xmigrate.migrate_begin(dom, dst)
+ val = xmigrate.migrate_begin(dominfo.id, dst)
print 'domain_migrate<', val
return val
@param progress: output progress if true
@return: deferred
"""
- dom = int(id)
+ dominfo = self.domain_lookup(id)
xmigrate = XendMigrate.instance()
- return xmigrate.save_begin(dom, dst)
+ return xmigrate.save_begin(dominfo.id, dst)
def domain_pincpu(self, dom, cpu):
"""Pin a domain to a cpu.
@param dom: domain
@param cpu: cpu number
"""
- dom = int(dom)
- return xc.domain_pincpu(dom, cpu)
+ dominfo = self.domain_lookup(id)
+ return xc.domain_pincpu(itn(dominfo.id), cpu)
- def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
+ def domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
"""Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
+ dominfo = self.domain_lookup(id)
+ return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
- def domain_cpu_bvt_get(self, dom):
+ def domain_cpu_bvt_get(self, id):
"""Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.bvtsched_domain_get(dom)
+ dominfo = self.domain_lookup(id)
+ return xc.bvtsched_domain_get(dominfo.dom)
- def domain_cpu_fbvt_set(self, dom, mcuadv, warp, warpl, warpu):
+ def domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu):
"""Set FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.fbvtsched_domain_set(dom=dom, mcuadv=mcuadv,
+ dominfo = self.domain_lookup(id)
+ return xc.fbvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
- def domain_cpu_fbvt_get(self, dom):
+ def domain_cpu_fbvt_get(self, id):
"""Get FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.fbvtsched_domain_get(dom)
+ dominfo = self.domain_lookup(id)
+ return xc.fbvtsched_domain_get(dominfo.dom)
- def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
+ def domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
"""Set Atropos scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
+ dominfo = self.domain_lookup(id)
+ return xc.atropos_domain_set(dominfo.dom, period, slice, latency, xtratime)
- def domain_cpu_atropos_get(self, dom):
+ def domain_cpu_atropos_get(self, id):
"""Get Atropos scheduler parameters for a domain.
"""
- dom = int(dom)
- return xc.atropos_domain_get(dom)
+ dominfo = self.domain_lookup(id)
+ return xc.atropos_domain_get(dominfo.dom)
- def domain_device_create(self, dom, devconfig):
+ def domain_device_create(self, id, devconfig):
"""Create a new device for a domain.
- @param dom: domain id
+ @param id: domain id
@param devconfig: device configuration
@return: deferred
"""
- dom = int(dom)
- dominfo = self.domain_get(dom)
- if not dominfo:
- raise XendError("invalid domain:" + str(dom))
+ dominfo = self.domain_lookup(id)
self.refresh_schedule()
val = dominfo.device_create(devconfig)
self.update_domain(dominfo.id)
return val
- def domain_device_destroy(self, dom, type, idx):
+ def domain_device_destroy(self, id, type, idx):
"""Destroy a device.
- @param dom: domain id
+ @param id: domain id
@param type: device type
@param idx: device index
"""
- dom = int(dom)
- dominfo = self.domain_get(dom)
- if not dominfo:
- raise XendError("invalid domain:" + str(dom))
+ dominfo = self.domain_lookup(id)
self.refresh_schedule()
val = dominfo.device_destroy(type, idx)
self.update_domain(dominfo.id)
return val
- def domain_devtype_ls(self, dom, type):
+ def domain_devtype_ls(self, id, type):
"""Get list of device indexes for a domain.
- @param dom: domain
+ @param id: domain
@param type: device type
@return: device indexes
"""
- dominfo = self.domain_get(dom)
- if not dominfo: return None
+ dominfo = self.domain_lookup(id)
devs = dominfo.get_devices(type)
- return range(0, len(devs))
+ #return range(0, len(devs))
+ return devs
- def domain_devtype_get(self, dom, type, idx):
+ def domain_devtype_get(self, id, type, idx):
"""Get a device from a domain.
- @param dom: domain
+ @param id: domain
@param type: device type
@param idx: device index
@return: device object (or None)
"""
- dominfo = self.domain_get(dom)
- if not dominfo: return None
+ dominfo = self.domain_lookup(id)
return dominfo.get_device_by_index(type, idx)
- def domain_vif_ls(self, dom):
+ def domain_vif_ls(self, id):
"""Get list of virtual network interface (vif) indexes for a domain.
- @param dom: domain
+ @param id: domain
@return: vif indexes
"""
- return self.domain_devtype_ls(dom, 'vif')
+ return self.domain_devtype_ls(id, 'vif')
- def domain_vif_get(self, dom, vif):
+ def domain_vif_get(self, id, vif):
"""Get a virtual network interface (vif) from a domain.
- @param dom: domain
+ @param id: domain
@param vif: vif index
@return: vif device object (or None)
"""
- return self.domain_devtype_get(dom, 'vif', vif)
+ return self.domain_devtype_get(id, 'vif', vif)
- def domain_vbd_ls(self, dom):
+ def domain_vbd_ls(self, id):
"""Get list of virtual block device (vbd) indexes for a domain.
- @param dom: domain
+ @param id: domain
@return: vbd indexes
"""
- return self.domain_devtype_ls(dom, 'vbd')
+ return self.domain_devtype_ls(id, 'vbd')
- def domain_vbd_get(self, dom, vbd):
+ def domain_vbd_get(self, id, vbd):
"""Get a virtual block device (vbd) from a domain.
- @param dom: domain
+ @param id: domain
@param vbd: vbd index
@return: vbd device (or None)
"""
- return self.domain_devtype_get(dom, 'vbd', vbd)
+ return self.domain_devtype_get(id, 'vbd', vbd)
- def domain_shadow_control(self, dom, op):
+ def domain_shadow_control(self, id, op):
"""Shadow page control.
- @param dom: domain
+ @param id: domain
@param op: operation
"""
- dom = int(dom)
- return xc.shadow_control(dom, op)
+ dominfo = self.domain_lookup(id)
+ return xc.shadow_control(dominfo.dom, op)
- def domain_maxmem_set(self, dom, mem):
+ def domain_maxmem_set(self, id, mem):
"""Set the memory limit for a domain.
@param dom: domain
@param mem: memory limit (in MB)
@return: 0 on success, -1 on error
"""
- dom = int(dom)
+ dominfo = self.domain_lookup(id)
maxmem = int(mem) * 1024
- return xc.domain_setmaxmem(dom, maxmem_kb = maxmem)
+ return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
def instance():
def add_config_handler(name, h):
"""Add a handler for a config field.
- name field name
- h handler: fn(vm, config, field, index)
+ @param name: field name
+ @param h: handler: fn(vm, config, field, index)
"""
config_handlers[name] = h
def add_image_handler(name, h):
"""Add a handler for an image type
- name image type
- h handler: fn(config, name, memory, image)
+ @param name: image type
+ @param h: handler: fn(config, name, memory, image)
"""
image_handlers[name] = h
def get_image_handler(name):
"""Get the handler for an image type.
- name image type
-
- returns handler or None
+ @param name: image type
+ @return: handler or None
"""
return image_handlers.get(name)
def add_device_handler(name, h):
"""Add a handler for a device type.
- name device type
- h handler: fn(vm, dev)
+ @param name: device type
+ @param h: handler: fn(vm, dev)
"""
device_handlers[name] = h
def get_device_handler(name):
"""Get the handler for a device type.
- name device type
-
- returns handler or None
+ @param name : device type
+ @return; handler or None
"""
return device_handlers.get(name)
If a vm has been partially created and there is an error it
is destroyed.
- config configuration
-
- returns Deferred
- raises VmError for invalid configuration
+ @param config configuration
+ @return: Deferred
+ @raise: VmError for invalid configuration
"""
vm = XendDomainInfo()
return vm.construct(config)
return deferred
def dom_get(dom):
+ """Get info from xen for an existing domain.
+
+ @param dom: domain id
+ @return: info or None
+ """
domlist = xc.domain_getinfo(dom=dom)
if domlist and dom == domlist[0]['dom']:
return domlist[0]
return None
-
def append_deferred(dlist, v):
+ """Append a value to a deferred list if it is a deferred.
+
+ @param dlist: list of deferreds
+ @param v: value to add
+ """
if isinstance(v, defer.Deferred):
dlist.append(v)
def _vm_configure1(val, vm):
d = vm.create_devices()
- def cbok(x):
- return x
- d.addCallback(cbok)
d.addCallback(_vm_configure2, vm)
return d
"""Minimum time between domain restarts in seconds.
"""
- MINIMUM_RESTART_TIME = 10
+ MINIMUM_RESTART_TIME = 20
def __init__(self):
self.recreate = 0
self.cmdline = None
self.console = None
self.devices = {}
+ self.device_index = {}
self.configs = []
self.info = None
self.ipaddrs = []
self.console_port = None
def setdom(self, dom):
+ """Set the domain id.
+
+ @param dom: domain id
+ """
self.dom = int(dom)
self.id = str(dom)
-
+
def update(self, info):
"""Update with info from xc.domain_getinfo().
"""
sxpr.append(['config', self.config])
return sxpr
+ def check_name(self, name):
+ """Check if a vm name is valid. Valid names start with a non-digit
+ and contain alphabetic characters, digits, or characters in '_-.'.
+ The same name cannot be used for more than one vm at the same time.
+
+ @param name: name
+ @raise: VMerror if invalid
+ """
+ if name is None or name == '':
+ raise VmError('missing vm name')
+ if name[0] in string.digits:
+ raise VmError('invalid vm name')
+ for c in name:
+ if c in string.digits: continue
+ if c in '_-.': continue
+ if c in string.ascii_letters: continue
+ raise VmError('invalid vm name')
+ # See comment in XendDomain constructor about 'xd'.
+ if xd.domain_exists(name):
+ raise VmError('vm name clash: ' + name)
+
def construct(self, config):
+ """Construct the vm instance from its configuration.
+
+ @param config: configuration
+ @return: deferred
+ @raise: VmError on error
+ """
# todo - add support for scheduling params?
self.config = config
try:
self.name = sxp.child_value(config, 'name')
- if self.name is None:
- raise VmError('missing domain name')
+ self.check_name(self.name)
self.memory = int(sxp.child_value(config, 'memory'))
if self.memory is None:
raise VmError('missing memory size')
raise VmError('unknown image type: ' + image_name)
image_handler(self, image)
deferred = self.configure()
- def cbok(x):
- return x
def cberr(err):
self.destroy()
return err
- deferred.addCallback(cbok)
deferred.addErrback(cberr)
except StandardError, ex:
# Catch errors, cleanup and re-raise.
def config_devices(self, name):
"""Get a list of the 'device' nodes of a given type from the config.
- name device type
- return list of device configs
+ @param name: device type
+ @type name: string
+ @return: device configs
+ @rtype: list
"""
devices = []
for d in sxp.children(self.config, 'device'):
return devices
def config_device(self, type, idx):
+ """Get a device config from the device nodes of a given type
+ from the config.
+
+ @param type: device type
+ @type type: string
+ @param idx: index
+ @type idx: int
+ @return config or None
+ """
devs = self.config_devices(type)
if 0 <= idx < len(devs):
return devs[idx]
else:
return None
+ def next_device_index(self, type):
+ """Get the next index for a given device type.
+
+ @param type: device type
+ @type type: string
+ @return device index
+ @rtype: int
+ """
+ idx = self.device_index.get(type, 0)
+ self.device_index[type] = idx + 1
+ return idx
+
def add_device(self, type, dev):
"""Add a device to a virtual machine.
- dev device to add
+ @param type: device type
+ @param dev: device to add
"""
dl = self.devices.get(type, [])
dl.append(dev)
self.devices[type] = dl
def get_devices(self, type):
+ """Get a list of the devices of a given type.
+
+ @param type: device type
+ @return: devices
+ """
val = self.devices.get(type, [])
return val
def get_device_by_id(self, type, id):
"""Get the device with the given id.
- id device id
-
- returns device or None
+ @param id: device id
+ @return: device or None
"""
dl = self.get_devices(type)
for d in dl:
def get_device_by_index(self, type, idx):
"""Get the device with the given index.
- idx device index
-
- returns device or None
+ @param idx: device index
+ @return: device or None
"""
+ idx = str(idx)
dl = self.get_devices(type)
- if 0 <= idx < len(dl):
- return dl[idx]
- else:
- return None
+ for d in dl:
+ if d.getidx() == idx:
+ return d
+ return None
def add_config(self, val):
"""Add configuration data to a virtual machine.
- val data to add
+ @param val: data to add
"""
self.configs.append(val)
def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
"""Create a domain. Builds the image but does not configure it.
- ostype OS type
- kernel kernel image
- ramdisk kernel ramdisk
- cmdline kernel commandline
- vifs_n number of network interfaces
+ @param ostype: OS type
+ @param kernel: kernel image
+ @param ramdisk: kernel ramdisk
+ @param cmdline: kernel commandline
+ @param vifs_n: number of network interfaces
"""
if not self.recreate:
if not os.path.isfile(kernel):
def create_devices(self):
"""Create the devices for a vm.
- returns Deferred
- raises VmError for invalid devices
+ @return: Deferred
+ @raise: VmError for invalid devices
"""
dlist = []
devices = sxp.children(self.config, 'device')
"""
dev = self.get_device_by_index(type, idx)
if not dev:
- raise VmError('invalid device: %s %d' % (type, idx))
+ raise VmError('invalid device: %s %s' % (type, idx))
devs = self.devices.get(type)
- if 0 <= idx < len(devs):
- del devs[idx]
- dev_config = self.config_device(type, idx)
+ index = devs.index(dev)
+ dev_config = self.config_device(type, index)
if dev_config:
self.config.remove(['device', dev_config])
dev.destroy()
def configure_console(self):
+ """Configure the vm console port.
+ """
x = sxp.child_value(self.config, 'console')
if x:
try:
self.console_port = port
def configure_restart(self):
+ """Configure the vm restart mode.
+ """
r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
if r not in restart_modes:
raise VmError('invalid restart mode: ' + str(r))
self.restart_mode = r;
def restart_needed(self, reason):
+ """Determine if the vm needs to be restarted when shutdown
+ for the given reason.
+
+ @param reason: shutdown reason
+ @return 1 if needs restaert, 0 otherwise
+ """
if self.restart_mode == RESTART_NEVER:
return 0
if self.restart_mode == RESTART_ALWAYS:
return 0
def restart_cancel(self):
+ """Cancel a vm restart.
+ """
self.restart_state = None
def restarting(self):
+ """Put the vm into restart mode.
+ """
self.restart_state = STATE_RESTART_PENDING
def restart_pending(self):
+ """Test if the vm has a pending restart.
+ """
return self.restart_state == STATE_RESTART_PENDING
def restart_check(self):
if self.restart_time is not None:
tdelta = tnow - self.restart_time
if tdelta < self.MINIMUM_RESTART_TIME:
- msg = 'VM %d restarting too fast' % self.dom
+ msg = 'VM %s restarting too fast' % self.name
log.error(msg)
raise VmError(msg)
self.restart_time = tnow
"""
if self.blkif_backend:
d = defer.Deferred()
- d.callback(1)
+ d.callback(self)
else:
d = xend.blkif_create(self.dom, recreate=self.recreate)
d.addCallback(_vm_configure1, self)
return d
def dom_configure(self, dom):
- """Configure a domain.
+ """Configure a vm for an existing domain.
- dom domain id
- returns deferred
+ @param dom: domain id
+ @return: deferred
"""
d = dom_get(dom)
if not d:
return deferred
def configure_fields(self):
+ """Process the vm configuration fields using the registered handlers.
+ """
dlist = []
index = {}
for field in sxp.children(self.config):
def vm_image_linux(vm, image):
"""Create a VM for a linux image.
- name vm name
- memory vm memory
- image image config
-
- returns vm
+ @param name: vm name
+ @param memory: vm memory
+ @param image: image config
+ @return: vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
def vm_image_netbsd(vm, image):
"""Create a VM for a bsd image.
- name vm name
- memory vm memory
- image image config
-
- returns vm
+ @param name: vm name
+ @param memory: vm memory
+ @param image: image config
+ @return: vm
"""
#todo: Same as for linux. Is that right? If so can unify them.
kernel = sxp.child_value(image, "kernel")
def vm_dev_vif(vm, val, index):
"""Create a virtual network interface (vif).
- vm virtual machine
- val vif config
- index vif index
+ @param vm: virtual machine
+ @param val: vif config
+ @param index: vif index
+ @return: deferred
"""
if vm.netif_backend:
raise VmError('vif: vif in netif backend domain')
- vif = index #todo
+ vif = vm.next_device_index('vif')
vmac = sxp.child_value(val, "mac")
xend.netif_create(vm.dom, recreate=vm.recreate)
log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
def vm_dev_vbd(vm, val, index):
"""Create a virtual block device (vbd).
- vm virtual machine
- val vbd config
- index vbd index
+ @param vm: virtual machine
+ @param val: vbd config
+ @param index: vbd index
+ @return: deferred
"""
if vm.blkif_backend:
raise VmError('vbd: vbd in blkif backend domain')
- vdev = index
+ vdev = vm.next_device_index('vif')
uname = sxp.child_value(val, 'uname')
if not uname:
raise VmError('vbd: Missing uname')
return defer
def parse_pci(val):
+ """Parse a pci field.
+ """
if isinstance(val, types.StringType):
radix = 10
if val.startswith('0x') or val.startswith('0X'):
return v
def vm_dev_pci(vm, val, index):
+ """Add a pci device.
+
+ @param vm: virtual machine
+ @param val: device configuration
+ @param index: device index
+ @return: 0 on success
+ """
bus = sxp.child_value(val, 'bus')
if not bus:
raise VmError('pci: Missing bus')
return rc
-def vm_field_vfr(vm, config, val, index):
- """Handle a vfr field in a config.
-
- vm virtual machine
- config vm config
- val vfr field
- """
- # Get the rules and add them.
- # (vfr (vif (id foo) (ip x.x.x.x)) ... )
- list = sxp.children(val, 'vif')
- ipaddrs = []
- for v in list:
- id = sxp.child_value(v, 'id')
- if id is None:
- raise VmError('vfr: missing vif id')
- id = int(id)
- dev = vm.get_device_by_index('vif', id)
- if not dev:
- raise VmError('vfr: invalid vif id %d' % id)
- vif = sxp.child_value(dev, 'vif')
- ip = sxp.child_value(v, 'ip')
- if not ip:
- raise VmError('vfr: missing ip address')
- ipaddrs.append(ip);
- # todo: Configure the ipaddrs.
- vm.ipaddrs = ipaddrs
-
-def vnet_bridge(vnet, vmac, dom, idx):
- """Add the device for the vif to the bridge for its vnet.
- """
- vif = "vif%d.%d" % (dom, idx)
- try:
- cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
- log.debug("vnet_bridge> %s", cmd)
- out = file("/proc/vnet/policy", "wb")
- out.write(cmd)
- err = out.close()
- log.debug("vnet_bridge> err=%d", err)
- except IOError, ex:
- log.exception("vnet_bridge>")
-
-def vm_field_vnet(vm, config, val, index):
- """Handle a vnet field in a config.
+def vm_field_ignore(vm, config, val, index):
+ """Dummy config field handler used for fields with built-in handling.
- vm virtual machine
- config vm config
- val vnet field
- index index
+ @param vm: virtual machine
+ @param config: vm config
+ @param val: vfr field
+ @param index: field index
"""
- # Get the vif children. For each vif look up the vif device
- # with the given id and configure its vnet.
- # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
- vif_vnets = sxp.children(val, 'vif')
- for v in vif_vnets:
- id = sxp.child_value(v, 'id')
- if id is None:
- raise VmError('vnet: missing vif id')
- dev = vm.get_device_by_id('vif', id)
- #vnet = sxp.child_value(v, 'vnet', 1)
- #mac = sxp.child_value(dev, 'mac')
- #vif = sxp.child_value(dev, 'vif')
- #vnet_bridge(vnet, mac, vm.dom, 0)
- #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
-
-def vm_field_ignore(vm, config, val, index):
pass
-# Register image handlers for linux and bsd.
+# Register image handlers.
add_image_handler('linux', vm_image_linux)
add_image_handler('netbsd', vm_image_netbsd)
-# Register device handlers for vifs and vbds.
+# Register device handlers.
add_device_handler('vif', vm_dev_vif)
add_device_handler('vbd', vm_dev_vbd)
add_device_handler('pci', vm_dev_pci)
add_config_handler('device', vm_field_ignore)
add_config_handler('backend', vm_field_ignore)
-# Register config handlers for vfr and vnet.
-add_config_handler('vfr', vm_field_vfr)
-add_config_handler('vnet', vm_field_vnet)
+# Register other config handlers.
def op_configure(self, op, req):
fn = FormFn(self.xd.domain_configure,
- [['dom', 'int'],
+ [['dom', 'str'],
['config', 'sxpr']])
- deferred = fn(req.args, {'dom': self.dom.id})
+ deferred = fn(req.args, {'dom': self.dom.name})
deferred.addErrback(self._op_configure_err, req)
return deferred
return str(err)
def op_unpause(self, op, req):
- val = self.xd.domain_unpause(self.dom.id)
+ val = self.xd.domain_unpause(self.dom.name)
return val
def op_pause(self, op, req):
- val = self.xd.domain_pause(self.dom.id)
+ val = self.xd.domain_pause(self.dom.name)
return val
def op_shutdown(self, op, req):
fn = FormFn(self.xd.domain_shutdown,
- [['dom', 'int'],
+ [['dom', 'str'],
['reason', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
req.setResponseCode(http.ACCEPTED)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
- [['dom', 'int'],
+ [['dom', 'str'],
['reason', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_save(self, op, req):
fn = FormFn(self.xd.domain_save,
- [['dom', 'int'],
+ [['dom', 'str'],
['file', 'str']])
- deferred = fn(req.args, {'dom': self.dom.id})
+ deferred = fn(req.args, {'dom': self.dom.name})
deferred.addCallback(self._op_save_cb, req)
deferred.addErrback(self._op_save_err, req)
return deferred
def op_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
- [['dom', 'int'],
+ [['dom', 'str'],
['destination', 'str']])
- deferred = fn(req.args, {'dom': self.dom.id})
+ deferred = fn(req.args, {'dom': self.dom.name})
print 'op_migrate>', deferred
deferred.addCallback(self._op_migrate_cb, req)
deferred.addErrback(self._op_migrate_err, req)
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
return str(err)
- def op_device_create(self, op, req):
- fn = FormFn(self.xd.domain_device_create,
- [['dom', 'int'],
- ['config', 'sxpr']])
- d = fn(req.args, {'dom': self.dom.id})
- return d
-
- def op_device_destroy(self, op, req):
- fn = FormFn(self.xd.domain_device_destroy,
- [['dom', 'int'],
- ['type', 'str'],
- ['index', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
def op_pincpu(self, op, req):
fn = FormFn(self.xd.domain_pincpu,
- [['dom', 'int'],
+ [['dom', 'str'],
['cpu', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_bvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_bvt_set,
- [['dom', 'int'],
+ [['dom', 'str'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_fbvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_fbvt_set,
- [['dom', 'int'],
+ [['dom', 'str'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
return val
def op_cpu_atropos_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_atropos_set,
- [['dom', 'int'],
+ [['dom', 'str'],
['period', 'int'],
['slice', 'int'],
['latency', 'int'],
['xtratime', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
return val
def op_maxmem_set(self, op, req):
fn = FormFn(self.xd.domain_maxmem_set,
- [['dom', 'int'],
+ [['dom', 'str'],
['memory', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ val = fn(req.args, {'dom': self.dom.name})
return val
+ def op_device_create(self, op, req):
+ fn = FormFn(self.xd.domain_device_create,
+ [['dom', 'str'],
+ ['config', 'sxpr']])
+ d = fn(req.args, {'dom': self.dom.name})
+ return d
+
+ def op_device_destroy(self, op, req):
+ fn = FormFn(self.xd.domain_device_destroy,
+ [['dom', 'str'],
+ ['type', 'str'],
+ ['idx', 'str']])
+ val = fn(req.args, {'dom': self.dom.name})
+ return val
+
def op_vifs(self, op, req):
- return self.xd.domain_vif_ls(self.dom.id)
+ devs = self.xd.domain_vif_ls(self.dom.name)
+ return [ dev.sxpr() for dev in devs ]
def op_vif(self, op, req):
fn = FormFn(self.xd.domain_vif_get,
- [['dom', 'int'],
- ['vif', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
+ [['dom', 'str'],
+ ['vif', 'str']])
+ val = fn(req.args, {'dom': self.dom.name})
return val
def op_vbds(self, op, req):
- return self.xd.domain_vbd_ls(self.dom.id)
+ devs = self.xd.domain_vbd_ls(self.dom.name)
+ return [ dev.sxpr() for dev in devs ]
def op_vbd(self, op, req):
fn = FormFn(self.xd.domain_vbd_get,
- [['dom', 'int'],
- ['vbd', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vbd_add(self, op, req):
- fn = FormFn(self.xd.domain_vbd_add,
- [['dom', 'int'],
- ['uname', 'str'],
- ['dev', 'str'],
- ['mode', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vbd_remove(self, op, req):
- fn = FormFn(self.xd.domain_vbd_remove,
- [['dom', 'int'],
- ['dev', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
+ [['dom', 'str'],
+ ['vbd', 'str']])
+ val = fn(req.args, {'dom': self.dom.name})
return val
def render_POST(self, req):
def domain(self, x):
val = None
- dom = self.xd.domain_get(x)
+ dom = self.xd.domain_lookup(x)
if not dom:
raise XendError('No such domain ' + str(x))
val = SrvDomain(dom)
def _op_create_cb(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
"""
- dom = dominfo.id
+ dom = dominfo.name
domurl = "%s/%s" % (req.prePathURL(), dom)
req.setResponseCode(http.CREATED, "created")
req.setHeader("Location", domurl)
return deferred
def _op_restore_cb(self, dominfo, req):
- dom = dominfo.id
+ dom = dominfo.name
domurl = "%s/%s" % (req.prePathURL(), dom)
req.setResponseCode(http.CREATED)
req.setHeader("Location", domurl)
sxp.show(domains, out=req)
else:
domains = self.xd.domains()
- domains.sort(lambda x, y: cmp(x.id, y.id))
+ domains.sort(lambda x, y: cmp(x.name, y.name))
req.write('<ul>')
for d in domains:
req.write('<li><a href="%s%s"> Domain %s</a>'
- % (url, d.id, d.id))
- req.write('name=%s' % d.name)
+ % (url, d.name, d.name))
+ req.write('id=%s' % d.id)
req.write('memory=%d'% d.memory)
req.write('</li>')
req.write('</ul>')
"""
def __init__(self, ctrl, vdev, mode, segment):
- controller.Dev.__init__(self, ctrl)
+ controller.Dev.__init__(self, segment['device'], ctrl)
self.vdev = vdev
self.mode = mode
self.device = segment['device']
return 'w' not in self.mode
def sxpr(self):
- val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
+ val = ['blkdev',
+ ['idx', self.idx],
+ ['vdev', self.vdev],
+ ['device', self.device],
+ ['mode', self.mode]]
return val
def destroy(self):
"""Abstract class for a device attached to a device controller.
"""
- def __init__(self, controller):
+ def __init__(self, idx, controller):
+ self.idx = str(idx)
self.controller = controller
self.props = {}
+ def getidx(self):
+ return self.idx
+
def setprop(self, k, v):
self.props[k] = v
"""
def __init__(self, ctrl, vif, config):
- controller.Dev.__init__(self, ctrl)
+ controller.Dev.__init__(self, vif, ctrl)
self.vif = vif
self.evtchn = None
self.configure(config)
def sxpr(self):
vif = str(self.vif)
mac = self.get_mac()
- val = ['vif', ['idx', vif], ['mac', mac]]
+ val = ['vif',
+ ['idx', self.idx],
+ ['vif', vif],
+ ['mac', mac]]
if self.bridge:
val.append(['bridge', self.bridge])
if self.script:
show(x, out)
i += 1
out.write(k_list_close)
+ elif isinstance(sxpr, (types.IntType, types.FloatType)):
+ out.write(str(sxpr))
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
else:
- #out.write("'" + str(sxpr) + "'")
out.write(repr(str(sxpr)))
def show_xml(sxpr, out=sys.stdout):
except XendError, ex:
opts.err(str(ex))
- dom = int(sxp.child_value(dominfo, 'id'))
+ dom = sxp.child_value(dominfo, 'name')
console_info = sxp.child(dominfo, 'console')
if console_info:
console_port = int(sxp.child_value(console_info, 'console_port'))
if server.xend_domain_unpause(dom) < 0:
server.xend_domain_destroy(dom)
- opts.err("Failed to unpause domain %d" % dom)
- opts.info("Started domain %d, console on port %d"
+ opts.err("Failed to unpause domain %s" % dom)
+ opts.info("Started domain %s, console on port %d"
% (dom, console_port))
return (dom, console_port)
return
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
- try:
- domid = int(dom)
- except:
- opts.err('Invalid domain: ' + dom)
if opts.vals.reboot:
mode = 'reboot'
else:
mode = 'halt'
- server.xend_domain_destroy(domid, mode)
+ server.xend_domain_destroy(dom, mode)
use_long = 1
if n == 0:
- doms = map(int, server.xend_domains())
+ doms = server.xend_domains()
doms.sort()
else:
- doms = map(int, params)
+ doms = params
if use_long:
self.long_list(doms)
self.brief_list(doms)
def brief_list(self, doms):
- print 'Dom Name Mem(MB) CPU State Time(s)'
+ print 'Name Id Mem(MB) CPU State Time(s) Console'
for dom in doms:
info = server.xend_domain(dom)
d = {}
- d['dom'] = int(dom)
+ d['dom'] = int(sxp.child_value(info, 'id', '-1'))
d['name'] = sxp.child_value(info, 'name', '??')
d['mem'] = int(sxp.child_value(info, 'memory', '0'))
d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
d['state'] = sxp.child_value(info, 'state', '??')
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
- print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d)
+ console = sxp.child(info, 'console')
+ if console:
+ d['port'] = sxp.child_value(console, 'console_port')
+ else:
+ d['port'] = ''
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f %(port)4s"
+ % d)
def long_list(self, doms):
for dom in doms:
info = server.xend_domain(dom)
- print '\nDomain %d' % dom
PrettyPrint.prettyprint(info)
xm.prog(ProgList)
from xen.xend.XendClient import server
from xen.xm.opts import *
+DOM0 = 'Domain-0'
+
gopts = Opts(use="""[options] [DOM]
Shutdown one or more domains gracefully.
use='Shutdown and reboot.')
def shutdown(opts, doms, mode, wait):
- def domains():
- return [ int(a) for a in server.xend_domains() ]
- if doms == None: doms = domains()
- if 0 in doms:
- doms.remove(0)
+ if doms == None: doms = server.xend_domains()
+ if DOM0 in doms:
+ doms.remove(DOM0)
for d in doms:
server.xend_domain_shutdown(d, mode)
if wait:
if d in alive: continue
dead.append(d)
for d in dead:
- opts.info("Domain %d terminated" % d)
+ opts.info("Domain %s terminated" % d)
doms.remove(d)
time.sleep(1)
opts.info("All domains terminated")
def main_dom(opts, args):
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
- try:
- domid = int(dom)
- except:
- opts.err('Invalid domain: ' + dom)
-
mode = shutdown_mode(opts)
- shutdown(opts, [ domid ], mode, opts.vals.wait)
+ shutdown(opts, [ dom ], mode, opts.vals.wait)
def main(argv):
opts = gopts
if opts.vals.help:
opts.usage()
return
- print 'shutdown.main>', len(args), args
if opts.vals.all:
main_all(opts, args)
else: